import { inject, reactive } from 'vue'
const StoreKey = 'store'

//定义一个公共的方法
function foreachValue(obj, callback) {
  Object.keys(obj).forEach((key) => callback(obj[key], key))
}
class Store {
  constructor(options) {
    const { state, getters, mutations, actions } = options
    const store = this
    store._state = reactive({ data: state })
    store._mutations = Object.create(null)
    store._actions = Object.create(null)
    store.getters = {}
    foreachValue(mutations, (mutationFn, key) => {
      store._mutations[key] = (payload) =>
        mutationFn.call(store, store.state, payload)
    })
    foreachValue(actions, (actionFn, key) => {
      store._actions[key] = (payload) => actionFn.call(store, store, payload)
    })
    foreachValue(getters, (getterFn, key) => {
      Object.defineProperty(store.getters, key, {
        get: () => getterFn(store.state, store.getters),
      })
    })
  }
  get state() {
    return this._state.data
  }
  commit = (type, payload) => {
    this._mutations[type](payload)
  }
  dispatch = (type, payload) => {
    this._actions[type](payload)
  }
  install(app, injectKey = StoreKey) {
    app.provide(injectKey, this)
    app.config.globalProperties.$store = this
  }
}
/**
 * @param options 创建store时传入的选项
 */
export function createStore(options) {
  return new Store(options)
}

export function useStore(injectKey = StoreKey) {
  return inject(injectKey)
}
